package com.flower.ApiGateway.untils;

import java.io.Serializable;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;


import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

@Component
public class JwtTokenUtil implements Serializable {

	private static final long serialVersionUID = -3301605591108950415L;

	private static final String CLAIM_KEY_ACCOUNTNAME = "sub";
	private static final String CLAIM_KEY_CREATED = "created";

	@Value("${jwt.app.secert}")
	private String secret;

	@Value("${jwt.app.expiration}")
	private Long expiration;

	@Value("${jwt.app.refreshthreshold}")
	private Long refreshThreshold;

	/**
	 * 从token中获取用户名
	 * 
	 * @param token
	 * @return String
	 */
	public String getAccountNameFromToken(String token) {
		String accountName;
		try {
			final Claims claims = getClaimsFromToken(token);
			accountName = claims.getSubject();
		} catch (Exception e) {
			accountName = null;
		}
		return accountName;
	}

	/**
	 * 获取token的创建时间
	 * 
	 * @param token
	 * @return Date
	 */
	public Date getCreatedDateFromToken(String token) {
		Date created;
		try {
			final Claims claims = getClaimsFromToken(token);
			created = new Date((Long) claims.get(CLAIM_KEY_CREATED));
		} catch (Exception e) {
			created = null;
		}
		return created;
	}

	/**
	 * 获取token的过期时间
	 * 
	 * @param token
	 * @return Date
	 */
	public Date getExpirationDateFromToken(String token) {
		Date expiration;
		try {
			final Claims claims = getClaimsFromToken(token);
			expiration = claims.getExpiration();
		} catch (Exception e) {
			expiration = null;
		}
		return expiration;
	}

	/**
	 * 生成token for ms
	 * 
	 * @param userInfo
	 * @return String
	 */
	public String generateToken(String userName) {
		Map<String, Object> claims = new HashMap<>();
		claims.put(CLAIM_KEY_ACCOUNTNAME, userName);
		claims.put(CLAIM_KEY_CREATED, new Date());
		return generateToken(claims, null);
	}

	/**
	 * 生成token for other system
	 * 
	 * @param userInfo
	 * @return String
	 */
	public String generateToken(String systemName, Date expirationDate) {
		Map<String, Object> claims = new HashMap<>();
		claims.put(CLAIM_KEY_ACCOUNTNAME, systemName);
		claims.put(CLAIM_KEY_CREATED, new Date());
		return generateToken(claims, expirationDate);
	}

	/**
	 * 生成token
	 * 
	 * @param claims
	 * @return String
	 */
	public String generateToken(Map<String, Object> claims, Date expirationDate) {
		Date ownExpirationDate = expirationDate != null ? expirationDate : generateExpirationDate();
		return Jwts.builder().setClaims(claims).setExpiration(ownExpirationDate)
				.signWith(SignatureAlgorithm.HS512, secret).compact();
	}

	/**
	 * 判断是否需要刷新token 是:返回新的token 否:返回null
	 * 
	 * @param token
	 * @return String
	 */
	public String needRefreshToken(String token) {
		String refreshedToken = null;
		Date expiration = null;
		try {
			final Claims claims = getClaimsFromToken(token);
			expiration = claims.getExpiration();
			if ((expiration.getTime() - System.currentTimeMillis()) < refreshThreshold * 1000) {
				claims.put(CLAIM_KEY_CREATED, new Date());
				refreshedToken = generateToken(claims, null);
			}
		} catch (Exception e) {
			refreshedToken = null;
		}
		return refreshedToken;
	}

	/**
	 * 刷新token
	 * 
	 * @param token
	 * @return String
	 */
	public String refreshToken(String token, Date expirationDate) {
		String refreshedToken;
		try {
			final Claims claims = getClaimsFromToken(token);
			claims.put(CLAIM_KEY_CREATED, new Date());
			refreshedToken = generateToken(claims, expirationDate);
		} catch (Exception e) {
			refreshedToken = null;
		}
		return refreshedToken;
	}

	/**
	 * 验证token
	 * 
	 * @param token
	 * @return Boolean
	 */
	public Boolean validateToken(String token) {
		if (!isTokenExpired(token)) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * 获取token中的 Claims
	 * 
	 * @param token
	 * @return Claims
	 */
	private Claims getClaimsFromToken(String token) {
		Claims claims;
		try {
			claims = Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
		} catch (Exception e) {
			claims = null;
		}
		return claims;
	}

	/**
	 * 验证token 是否过期
	 * 
	 * @param token
	 * @return true:过期 false:不过期
	 */
	private Boolean isTokenExpired(String token) {
		final Date expiration = getExpirationDateFromToken(token);
		if (expiration != null) {
			return expiration.before(new Date());
		}
		return true;
	}

	private Date generateExpirationDate() {
		return new Date(System.currentTimeMillis() + expiration * 1000);
	}

}